﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using IntoNails.Infrastructure.DataAccess;
using IntoNails.Infrastructure.Extensions;
using IntoNails.Models;

namespace IntoNails.DataAccess
{
    public class ServiceRepository : AbstractDataRepository<Service, Guid>, IServiceRepository, IDataFileRepository
    {
        public ServiceRepository(string dataFile)
        {
            this.DataFilePath = dataFile;
        }

        #region Overrides of AbstractDataRepository<Service,Guid>

        public override Service Get(Guid uniqueCode)
        {
            return this.InnerDataList.SingleOrDefault(nails => nails.UniqueCode == uniqueCode);
        }

        public override IEnumerable<Service> Get(Func<Service, bool> predicate)
        {
            return this.InnerDataList.Where(predicate);
        } 

        public override IList<Service> GetRawItemList()
        {
            return this.InnerDataList;
        }

        public override void Add(Service item)
        {
            if (null == item)
            {
                this.OnDataAdded(new DataEventArgs<Service>(new ArgumentNullException("item")));
            }
            else if (this.InnerDataList.Contains(item))
            {
                this.OnDataAdded(new DataEventArgs<Service>(false));
            }
            else
            {
                this.InnerDataList.Add(item);
                this.OnDataAdded(new DataEventArgs<Service>(true));
            }
        }

        public override void Remove(Guid uniqueCode)
        {
            Service removedService = this.Get(uniqueCode);
            if (null == removedService)
            {
                this.OnDataRemoved(new DataEventArgs<Service>(new ArgumentNullException("uniqueCode")));
            }
            else
            {
                this.InnerDataList.Remove(removedService);
                this.OnDataRemoved(new DataEventArgs<Service>(true));
            }
        }

        public override void Update(Guid oldItemKey, Service newItem)
        {
            Service oldService = this.Get(oldItemKey);
            if (null == oldService)
            {
                this.Add(newItem);
            }
            else if (null == newItem)
            {
                this.OnDataUpdated(new DataUpdatedEventArgs<Service>(new ArgumentNullException("newItem")));
            }
            else
            {
                oldService.DisplayName = newItem.DisplayName;
                oldService.Minutes = newItem.Minutes;
                oldService.Price = newItem.Price;
                oldService.AssociatedCategory = newItem.AssociatedCategory;
                oldService.UpdatedDate = DateTime.Today;
                oldService.IsValid = newItem.IsValid;

                this.OnDataUpdated(new DataUpdatedEventArgs<Service>(true));
            }
        }

        public override void Save()
        {
            using (Stream saveDataStream = new FileStream(this.DataFilePath, FileMode.OpenOrCreate, FileAccess.Write))
            {
                this.InnerDataList.Serialize(saveDataStream);
            }
        }

        public override int Load()
        {
            if (!File.Exists(this.DataFilePath))
            {
                this.InnerDataList = new List<Service>();
            }
            else
            {
                using (Stream loadDataStream = new FileStream(this.DataFilePath, FileMode.Open, FileAccess.Read))
                {
                    this.InnerDataList = loadDataStream.Deserialize<List<Service>>();
                }
            }

            return this.InnerDataList.Count;
        }

        public override void Initialize()
        {
            this.InnerDataList = new List<Service>();
        }

        #endregion

        #region Implementation of IServiceRepository

        public IList<Service> GetNailsServicesByCategoryCode(Guid categoryCode)
        {
            return this.InnerDataList.Where(nails => nails.AssociatedCategory.UniqueCode == categoryCode && nails.IsValid).ToList();
        }

        #endregion

        #region Implementation of IDataFileRepository

        public string DataFilePath { get; set; }

        #endregion
    }
}
